package com.github.ilioili.justdoit.widget;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;

/**
 * Created by hantuo on 16/5/25.
 */
public class SatelliteView extends ViewGroup implements ValueAnimator.AnimatorUpdateListener {
    private ViewGroup windowContentRoot;
    private View anchorView;
    private ValueAnimator valueAnimator;
    private float startAngle;
    private float endAngle;
    private float radius;
    private int cx;
    private int cy;
    private boolean drawAnchor;
    private boolean isOpen;
    private Bitmap viewCache;

    public SatelliteView(Context context) {
        this(context, null);
    }

    public SatelliteView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SatelliteView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SatelliteView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(getContext().getResources().getInteger(android.R.integer.config_longAnimTime));
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(this);
        setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                collapse();
            }
        });
        setFocusable(true);
        setFocusableInTouchMode(true);
        setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                    clearFocus();
                    collapse();
                    return true;
                }
                return false;
            }
        });
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (drawAnchor && null != viewCache && !viewCache.isRecycled())
            canvas.drawBitmap(viewCache, cx - anchorView.getWidth() / 2, cy - anchorView.getHeight() / 2, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int hegith = MeasureSpec.getSize(heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(width, hegith);
    }

    private int getNotGoneChildCount(){
        int num=0;
        for(int i=0;i <getChildCount();i++){
            if(getChildAt(i).getVisibility()!=View.GONE) num++;
        }
        return num;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (isInEditMode()) {
            cx = getMeasuredWidth() / 2;
            cy = getMeasuredHeight() / 2;
            startAngle = 0;
            radius = cx < cy ? cx / 3 : cy / 3;
        }
        float angle = endAngle - startAngle;
        int divideNum = angle > 300 ? getNotGoneChildCount() : getNotGoneChildCount() - 1;
        float interval = angle / divideNum;
        int index = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                int viewCenterX = (int) (cx + radius * Math.sin((startAngle + index * interval) * Math.PI / 180));
                int viewCenterY = (int) (cy + radius * Math.cos((startAngle + index * interval) * Math.PI / 180));
                child.layout(viewCenterX - child.getMeasuredWidth() / 2, viewCenterY - child.getMeasuredHeight() / 2, viewCenterX + child.getMeasuredWidth() / 2, viewCenterY + child.getMeasuredHeight() / 2);
                index++;
            }
        }
    }

    /**
     * @param anchor
     * @param radius
     * @param startAngle 0~360
     * @param endAngle   0~360
     */
    public void expand(View anchor, float radius, float startAngle, float endAngle) {
        expand(anchor, true, radius, startAngle, endAngle);
    }

    /**
     * @param anchor
     * @param radius
     * @param startAngle 0~360
     * @param endAngle   0~360
     */
    public void expand(View anchor, boolean drawAnchor, float radius, float startAngle, float endAngle) {
        if(isOpen) return;
        isOpen = true;
        anchorView = anchor;
        this.drawAnchor = drawAnchor;
        requestFocus();
        this.startAngle = startAngle;
        this.endAngle = endAngle;
        this.radius = radius;
        anchor.destroyDrawingCache();
        anchor.buildDrawingCache();
        viewCache = anchor.getDrawingCache();
        int[] loc = new int[2];
        anchor.getLocationInWindow(loc);
        cx = loc[0] + anchor.getWidth() / 2;
        cy = loc[1] + anchor.getHeight() / 2;
        initWindowContentView();
        valueAnimator.setFloatValues(0, 1);
        valueAnimator.start();
    }

    public void collapse() {
        if(!isOpen) return;
        isOpen = false;
        valueAnimator.setFloatValues(1, 0);
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                windowContentRoot.removeView(SatelliteView.this);
                valueAnimator.removeAllListeners();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        valueAnimator.start();
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        for(int i=0; i<getChildCount(); i++){
            getChildAt(i).buildDrawingCache();
        }
    }

    private void initWindowContentView() {
        ViewGroup viewGroup = (ViewGroup) anchorView.getParent();
        while (viewGroup.getId() != Window.ID_ANDROID_CONTENT) {
            viewGroup = (ViewGroup) viewGroup.getParent();
        }
        windowContentRoot = viewGroup;
        if(getParent()!=null){
            ViewGroup vg = (ViewGroup) getParent();
            vg.removeView(this);
        }
        windowContentRoot.addView(this);
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        float angle = endAngle - startAngle;
        int divideNum = angle > 300 ? getNotGoneChildCount() : getNotGoneChildCount() - 1;
        float interval = angle / divideNum;
        int index = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                int viewCenterX = (int) (cx + radius * value * Math.sin((startAngle + index * interval) * Math.PI / 180 - 3 * (1 - value)));
                int viewCenterY = (int) (cy + radius * value * Math.cos((startAngle + index * interval) * Math.PI / 180 - 3 * (1 - value)));
                child.layout(viewCenterX - child.getMeasuredWidth() / 2, viewCenterY - child.getMeasuredHeight() / 2, viewCenterX + child.getMeasuredWidth() / 2, viewCenterY + child.getMeasuredHeight() / 2);
                index++;
            }
        }
        setAlpha(value);
    }
}
